//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Object properties dialog.
//

# include "StdAfx.h"
# include "Resource.h"
# include "RgnProperties.h"
# include "Map.h"
# include "Types.h"
# include "HoluxTypes.h"
# include "Label.h"
# include "Rename.h"
# include "SetComment.h"
# include "SetDirIndicator.h"
# include "ChangeType.h"
# include "TypeHelpers.h"
# include "MapView.h"
# include "PropertyPages.h"
# include "Button.h"
# include "Menu.h"
# include "Settings.h"
# include "Globals.h"

static bool g_bRefreshRequired;

static
void _ShowRgnProperties (HWND _hWnd, rgn_t & _rgn, size_t _cPoint) {
	CCritSec::CLock lock (g_cs);

	CPropertyPages rp;

	if (_rgn.IsWTR ()) {
		// Main.
		if (_rgn.IsWaypoint ())
			rp.AddPage (new CWptPage (_rgn));
		else if (_rgn.IsTrack ()) {
			rp.AddPage (new CTrackPage (_rgn));
			rp.AddPage (new CTrackPointsPage (_rgn, _cPoint));
		} else if (_rgn.IsRoute ())
			rp.AddPage (new CRoutePage (_rgn));

		// Source.
		rp.AddPage (new CRgnSourcePage (_rgn));
	} else {
		// Main.
		rp.AddPage (new CRgnPage (_rgn));

		// Elements.
		rp.AddPage (new CRgnElementsPage (_rgn));

		// Postal address.
		rp.AddPage (new CRgnAddressPage (g_map.pTypeSet == & g_tsHolux ? IDD_RGN_PA_HOLUX : IDD_RGN_PA, _rgn));

		// Info.
		const bool bHasContactOrDescription = g_map.pTypeSet->pfHasContact (_rgn) || g_map.pTypeSet->pfHasDescription (_rgn);
		if (g_map.pTypeSet->pfHasPhone (_rgn) || bHasContactOrDescription)
			rp.AddPage (new CRgnInfoPage (bHasContactOrDescription ? IDD_RGN_INFO : IDD_RGN_PHONE, _rgn));

		// Highway exit facilities.
		if (g_map.pTypeSet->pfIsHwExit (_rgn))
			rp.AddPage (new CRgnExitsPage (_rgn));

		// Routing.
		if (g_map.pTypeSet != & g_tsHolux && _rgn.IsPolyline () && g_map.pTypeSet->pfIsRoad (_rgn))
			rp.AddPage (new CRgnRoutingPage (_rgn));

		// Source.
		rp.AddPage (new CRgnSourcePage (_rgn));

		// Extras.
		rp.AddPage (new CRgnExtrasPage (_rgn));
	}

	size_t cStartPage = 0;
	const size_t cStartPageId = GetSetting ("RgnPropertiesPage", (DWORD) ppMain);
	const size_t cPages = rp.GetPages ();
	for (size_t c = 0; c < cPages; ++ c) {
		CRgnPPageBase * const pPage = static_cast<CRgnPPageBase *> (rp.GetPage (c));
		if ((size_t) pPage->GetId () == cStartPageId) {
			cStartPage = c;
			break;
		}
	}

	UINT uiTitle;
	if (_rgn.IsWTR ()) {
		if (_rgn.IsWaypoint ())
			uiTitle = IDS_WAYPOINT_PROPERTIES;
		else if (_rgn.IsTrack ())
			uiTitle = IDS_TRACK_PROPERTIES;
		else if (_rgn.IsRoute ())
			uiTitle = IDS_ROUTE_PROPERTIES;
	} else
		uiTitle = IDS_OBJECT_PROPERTIES;

	g_bRefreshRequired = false;

	rp.ShowModal (_hWnd, uiTitle, cStartPage);

	if (g_bRefreshRequired)
		Refresh ();
}

void ShowRgnProperties (HWND _hWnd, const find_info_t & _Selection) {
	if (! _Selection.pLayer)
		return;

	_ShowRgnProperties (_hWnd, * _Selection.iRgn, _Selection.cPoint);
}

void ShowRgnProperties (HWND _hWnd, rgn_t & _rgn) {
	_ShowRgnProperties (_hWnd, _rgn, -1);
}

//////////////////////////////////////////////////////////////////////////////

void CRgnPPageBase::RefreshRequired () {
	g_bRefreshRequired = true;
}

void CRgnPPageBase::OnActivatePage (const PSHNOTIFY *) {
	if (m_RgnPP != ppDontSave)
		SaveSetting ("RgnPropertiesPage", (DWORD) m_RgnPP);
}

//////////////////////////////////////////////////////////////////////////////

static string_t g_strLabelLast;

void CRgnPage::_FillType (USHORT _ushType) {
	if (m_rgn.IsTrack ())
		SetDlgItemText (IDC_TYPE, GetStr (IDS_TRACK));
	else if (m_rgn.IsRoute ())
		SetDlgItemText (IDC_TYPE, GetStr (IDS_ROUTE));
	else if (m_rgn.IsWaypoint ()) {
		const type_desc_t * const pTD = g_map.pTypeSet->GetTypeDesc (_ushType, m_rgn.Kind);
		assert (m_rgn.Kind < rkMax);
		SetDlgItemTextF (IDC_TYPE, "%s (0x%x, %s)", pTD ? pTD->strTypeName : GetStr (IDS_UNKNOWN), _ushType, GetStr (IDS_WAYPOINT));
	} else
		FillType (m_hWnd, IDC_TYPE, (RGN_KIND) m_rgn.Kind, _ushType);
}

bool CRgnPage::OnInit (HWND _hwndFocus) {
	// Type.
	m_ushType = m_rgn.ushType;
	_FillType (m_ushType);

	// Label.
	SetDlgItemText (IDC_LABEL, m_rgn.strLabel.c_str ());
	SetButtonIcon (m_hWnd, IDC_LABEL_SPECIAL, IDI_DOWN);
	EnableDlgItem (IDC_LABEL_LAST, ! g_strLabelLast.empty ());

	// Comment.
	SetDlgItemText (IDC_COMMENT, m_rgn.strComment.c_str ());

	// DirIndicator.
	CheckDlgButton (IDC_DIRINDICATOR, (m_rgn.dwFlags & rgn_t::fDirIndicator) != 0);
	if (! m_rgn.IsPolyline ())
		EnableDlgItem (IDC_DIRINDICATOR, false);

	// Points.
	size_t cNodes = 0;
	size_t cElements = 0;
	for (size_t cElement = 0; cElement < m_rgn.elements.size (); ++ cElement) {
		const rgn_element_t & element = m_rgn.elements [cElement];
		if (element.bDeleted)
			continue;

		cNodes += element.points.size ();
		++ cElements;
	}
	for (size_t cOrigin = 0; cOrigin < m_rgn.origins.size (); ++ cOrigin) {
		const rgn_origin_t & origin = m_rgn.origins [cOrigin];
		if (origin.bDeleted)
			continue;

		++ cNodes;
		++ cElements;
	}
	SetDlgItemTextF (IDC_ELEMENTS,    "%d", cElements);
	SetDlgItemTextF (IDC_TOTAL_NODES, "%d", cNodes);

	::SetFocus (GetDlgItem (IDC_LABEL));
	return false;
}

void CRgnPage::_AddSpecialCodeToLabel (const char * _str) {
	::SendDlgItemMessage (m_hWnd, IDC_LABEL, EM_REPLACESEL, TRUE, reinterpret_cast<LPARAM> (_str));
}

void CRgnPage::OnCommand (WORD _wCmd, WORD _wNotifyCode, HWND _hwndCtl) {
	switch (_wCmd) {
		case IDC_CHANGE_TYPE:
			if (ShowChangeType (m_hWnd, static_cast<RGN_KIND> (m_rgn.Kind), m_ushType)) {
				_FillType (m_ushType);
				PropSheetChanged ();
			}
			break;

		case IDC_DIRINDICATOR:
			if (_wNotifyCode == BN_CLICKED)
				PropSheetChanged ();
			break;

		case IDC_LABEL:
		case IDC_COMMENT:
			if (_wNotifyCode == EN_UPDATE)
				PropSheetChanged ();
			break;

		case IDC_LABEL_LAST:
			SetDlgItemText (IDC_LABEL, g_strLabelLast.c_str ()); break;
			break;

		case IDC_LABEL_SPECIAL: {
			static DWORD g_dwCancelTime_ShowSpecial;
			if (::GetTickCount () - g_dwCancelTime_ShowSpecial < 200)
				// NOTE: this click to arrow button is to close previous pop-up menu.
				break;

			CPopupMenu pm (::GetSubMenu (LoadMenu (g_map.Header.CodeSchema == bpsAscii7 ? IDM_LABEL_SPECIAL6 : IDM_LABEL_SPECIAL), 0));

			RECT rect;
			::GetWindowRect (_hwndCtl, & rect);

			const int nCmd = pm.ShowAsPopup (m_hWnd, rect);
			if (nCmd <= 0)
				g_dwCancelTime_ShowSpecial = ::GetTickCount ();
			else
				SendMessage (m_hWnd, WM_COMMAND, nCmd, 0);

			break;
		}

		case IDC_SPECIAL_LOWERCASE:           _AddSpecialCodeToLabel ("~[0x1b]"); break;
		case IDC_SPECIAL_HIDE_PREFIX2:        _AddSpecialCodeToLabel ("~[0x1b2b]"); break;
		case IDC_SPECIAL_HIDE_SUFFIX2:        _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x1b2c]" : "~[0x1c]"); break;
		case IDC_SPECIAL_HIDE_PREFIX:         _AddSpecialCodeToLabel ("~[0x1e]"); break;
		case IDC_SPECIAL_HIDE_SUFFIX:         _AddSpecialCodeToLabel ("~[0x1f]"); break;

		case IDC_SPECIAL_HIGHWAY_INTERSTATE:  _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2a]" : "~[0x01]"); break;
		case IDC_SPECIAL_HIGHWAY_SHIELD:      _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2b]" : "~[0x02]"); break;
		case IDC_SPECIAL_HIGHWAY_ROUND:       _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2c]" : "~[0x03]"); break;
		case IDC_SPECIAL_HIGHWAY_SMALL_BR:    _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2d]" : "~[0x04]"); break;
		case IDC_SPECIAL_HIGHWAY_BIG:         _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2e]" : "~[0x05]"); break;
		case IDC_SPECIAL_HIGHWAY_SMALL_WHITE: _AddSpecialCodeToLabel (g_map.Header.CodeSchema == bpsAscii7 ? "~[0x2f]" : "~[0x06]"); break;
	}
}

void CRgnPage::OnApply (const PSHNOTIFY *) {
	bool bRefresh = false;

	// Label.
	const HWND hLabel = GetDlgItem (IDC_LABEL);
	const size_t cLabelLen = ::GetWindowTextLength (hLabel);
	char * const strLabel = reinterpret_cast<char *> (alloca (cLabelLen + 1));
	::GetWindowText (hLabel, strLabel, cLabelLen + 1);
	if (g_map.Header.CodeSchema == bpsAscii7 && ! Is6bitLabelCorrect (strLabel)) {
		ErrorMsgBox ("The label includes symbols not allowed for ASCII-7 coding (currently selected).");
		SetMsgResult (PSNRET_INVALID);
		return;
	}
	if (! (m_rgn.strLabel == strLabel)) {
		g_strLabelLast = strLabel;
		RenameObject (m_rgn, strLabel);
		RefreshRequired ();
	}

	// Comment.
	const HWND hComment = GetDlgItem (IDC_COMMENT);
	const size_t cCommentLen = ::GetWindowTextLength (hComment);
	char * const strComment = reinterpret_cast<char *> (alloca (cCommentLen + 1));
	::GetWindowText (hComment, strComment, cCommentLen + 1);
	if (! (m_rgn.strComment == strComment)) {
		SetComment (m_rgn, strComment);
		RefreshRequired ();
	}

	// Type.
	if (m_rgn.ushType != m_ushType) {
		ChangeType (m_rgn, m_ushType);
		RefreshRequired ();
	}

	// DirIndicator.
	const bool bOldDirIndicator = (m_rgn.dwFlags & rgn_t::fDirIndicator) != 0;
	const bool bDirIndicator = IsDlgButtonChecked (IDC_DIRINDICATOR);
	if (bDirIndicator != bOldDirIndicator) {
		SetDirIndicator (m_rgn, bDirIndicator);
		RefreshRequired ();
	}
}
